package org.zj.webview.type;

import org.zj.webview.WebViewApi;
import org.zj.webview.listener.QueryListener;
import org.zj.webview.listener.WindowCloseListener;
import org.zj.webview.listener.WindowDestroyListener;

import java.util.*;

/**
 * 窗体的引用
 * 所有方法都应该在UI线程执行
 *
 * @author zj
 * @since 2025/3/31
 */
public class WebWindow extends NativeRef {
    private static final Map<Integer, List<Pair<Integer, QueryListener>>> QUERY_MAP = new HashMap<>();
    private static final Map<Integer, List<Pair<Integer, WindowCloseListener>>> WINDOW_CLOSE_MAP = new HashMap<>();
    private static final Map<Integer, List<Pair<Integer, WindowDestroyListener>>> WINDOW_DESTROY_MAP = new HashMap<>();

    private WebWindow() {
    }

    /**
     * 创建一个窗口
     *
     * @return
     */
    @Override
    public boolean isValid() {
        WebViewApi.checkUIThread();
        return isValid_();
    }

    /**
     * 获取窗口ID
     *
     * @return
     */
    public int getWindowId() {
        WebViewApi.checkUIThread();
        return this.getWindowId_();
    }

    /**
     * 获取窗口句柄
     *
     * @return
     */
    public HWND getWindowHandle() {
        WebViewApi.checkUIThread();
        return this.getWindowHandle_();
    }

    /**
     * 设置窗口是否可用
     *
     * @param enable
     */
    public void setWindowEnable(boolean enable) {
        WebViewApi.checkUIThread();
        this.setWindowEnable_(enable);
    }

    /**
     * 获取窗口是否可用
     *
     * @return
     */
    public boolean isWindowEnabled() {
        WebViewApi.checkUIThread();
        return this.isWindowEnabled_();
    }

    /**
     * 设置窗口是否可改变大小
     *
     * @param resizable
     */
    public void setWindowResizable(boolean resizable) {
        WebViewApi.checkUIThread();
        this.setWindowResizable_(resizable);
    }

    /**
     * 运行在UI线程
     *
     * @param runnable
     */
    public void runLater(Runnable runnable) {
        this.runOnUI_(new UiTask(runnable));
    }

    /**
     * 获取窗口DPI
     *
     * @return
     */
    public int getWindowDpi() {
        WebViewApi.checkUIThread();
        return this.getWindowDpi_();
    }

    /**
     * 激活窗口
     */
    public void activeWindow() {
        WebViewApi.checkUIThread();
        this.activeWindow_();
    }

    /**
     * 设置窗口置顶
     *
     * @param topmost
     */
    public void setWindowTopMost(boolean topmost) {
        WebViewApi.checkUIThread();
        this.setWindowTopMost_(topmost);
    }

    /**
     * 获取窗口是否置顶
     *
     * @return
     */
    public boolean isWindowTopMost() {
        WebViewApi.checkUIThread();
        return this.isWindowTopMost_();
    }

    /**
     * 移动窗口
     *
     * @param x
     * @param y
     * @param width
     * @param height
     */
    public void moveWindow(int x, int y, int width, int height) {
        WebViewApi.checkUIThread();
        this.moveWindow_(x, y, width, height);
    }

    /**
     * 改变窗口大小
     *
     * @param width
     * @param height
     */
    public void resizeWindow(int width, int height) {
        WebViewApi.checkUIThread();
        this.resizeWindow_(width, height);
    }

    /**
     * 显示窗口
     *
     * @param showType
     */
    public void showWindow(ShowType showType) {
        WebViewApi.checkUIThread();
        this.showWindow_(showType.getValue());
    }

    /**
     * 最大化窗口
     *
     * @param maximize
     */
    public void maximizeWindow(boolean maximize) {
        WebViewApi.checkUIThread();
        this.maximizeWindow_(maximize);
    }

    /**
     * 最小化窗口
     */
    public void minimizeWindow() {
        WebViewApi.checkUIThread();
        this.minimizeWindow_();
    }

    /**
     * 窗口是否可见
     *
     * @return
     */
    public boolean isWindowVisible() {
        WebViewApi.checkUIThread();
        return this.isWindowVisible_();
    }

    /**
     * 关闭窗口
     *
     * @param force
     */
    public void closeWindow(boolean force) {
        WebViewApi.checkUIThread();
        this.closeWindow_(force);
    }

    /**
     * 获取窗口矩形
     *
     * @return
     */
    public Rect getWindowRect() {
        WebViewApi.checkUIThread();
        return this.getWindowRect_();
    }

    /**
     * 获取窗口客户区矩形
     *
     * @return
     */
    public Rect getClientRect() {
        WebViewApi.checkUIThread();
        return this.getClientRect_();
    }

    /**
     * 闪烁窗口
     */
    public void flashWindow() {
        WebViewApi.checkUIThread();
        this.flashWindow_();
    }

    /**
     * 闪烁窗口
     *
     * @param dwFlags
     * @param uCount
     * @param dwTimeout
     */
    public void flashWindowEx(FlashFlags dwFlags, int uCount, int dwTimeout) {
        WebViewApi.checkUIThread();
        this.flashWindowEx_(dwFlags.getValue(), uCount, dwTimeout);
    }

    /**
     * 获取窗口状态
     *
     * @return
     */
    public int getWindowStatus() {
        WebViewApi.checkUIThread();
        return this.getWindowStatus_();
    }

    /**
     * 获取窗口标题
     *
     * @return
     */
    public String getWindowTitle() {
        WebViewApi.checkUIThread();
        return this.getWindowTitle_();
    }

    /**
     * 设置窗口标题
     *
     * @param title
     */
    public void setWindowTitle(String title) {
        WebViewApi.checkUIThread();
        this.setWindowTitle_(title);
    }

    /**
     * 调试窗口
     */
    public void openDevTools() {
        WebViewApi.checkUIThread();
        this.openDevTools_();
    }

    /**
     * 加载URL
     *
     * @param url
     */
    public void loadUrl(String url) {
        WebViewApi.checkUIThread();
        this.loadUrl_(url);
    }

    /**
     * 加载HTML字符串
     *
     * @param html
     */
    public void loadHtmlString(String html) {
        WebViewApi.checkUIThread();
        this.loadHtmlString_(html);
    }

    /**
     * 重新加载URL
     */
    public void reloadUrl() {
        WebViewApi.checkUIThread();
        this.reloadUrl_();
    }


    /**
     * 查询回调
     *
     * @param index
     * @param jsonString
     * @return
     */
    public void queryCallback(int index, boolean success, String jsonString) {
        WebViewApi.checkUIThread();
        this.queryCallback_(index, success, jsonString);
    }

    /**
     * 分发事件
     *
     * @param eventName
     * @param jsonString
     */
    public void dispatchEvent(String eventName, String jsonString) {
        WebViewApi.checkUIThread();
        this.dispatchEvent_(eventName, jsonString);
    }


    /**
     * 添加查询监听
     *
     * @param callback
     * @return
     */
    public boolean addQueryListener(QueryListener callback) {
        WebViewApi.checkUIThread();
        int ret = addQueryListener_(callback);
        if (ret == 0) {
            return false;
        }
        QUERY_MAP.computeIfAbsent(getWindowId(), k -> new ArrayList<>()).add(new Pair<>(ret, callback));
        return true;
    }

    /**
     * 移除查询监听
     *
     * @param callback
     */
    public void removeQueryListener(QueryListener callback) {
        WebViewApi.checkUIThread();
        List<Pair<Integer, QueryListener>> listeners = QUERY_MAP.get(getWindowId());
        if (listeners == null) {
            return;
        }
        Iterator<Pair<Integer, QueryListener>> iterator = listeners.iterator();
        while (iterator.hasNext()) {
            Pair<Integer, QueryListener> pair = iterator.next();
            if (Objects.equals(pair.getValue(), callback)) {
                removeQueryListener_(pair.getKey());
                iterator.remove();
            }
        }
    }

    /**
     * 添加窗口关闭监听
     *
     * @param callback
     * @return
     */
    public boolean addWindowCloseEventListener(WindowCloseListener callback) {
        WebViewApi.checkUIThread();
        int ret = addWindowCloseEventListener_(callback);
        if (ret == 0) {
            return false;
        }
        WINDOW_CLOSE_MAP.computeIfAbsent(getWindowId(), k -> new ArrayList<>()).add(new Pair<>(ret, callback));
        return true;
    }

    /**
     * 移除窗口关闭监听
     *
     * @param callback
     */
    public void removeWindowCloseEventListener(WindowCloseListener callback) {
        WebViewApi.checkUIThread();
        List<Pair<Integer, WindowCloseListener>> listeners = WINDOW_CLOSE_MAP.get(getWindowId());
        if (listeners == null) {
            return;
        }
        Iterator<Pair<Integer, WindowCloseListener>> iterator = listeners.iterator();
        while (iterator.hasNext()) {
            Pair<Integer, WindowCloseListener> pair = iterator.next();
            if (Objects.equals(pair.getValue(), callback)) {
                removeWindowCloseEventListener_(pair.getKey());
                iterator.remove();
            }
        }
    }

    /**
     * 添加窗口销毁监听
     *
     * @param callback
     * @return
     */
    public boolean addWindowDestroyEventListener(WindowDestroyListener callback) {
        WebViewApi.checkUIThread();
        int ret = addWindowDestroyEventListener_(callback);
        if (ret == 0) {
            return false;
        }
        WINDOW_DESTROY_MAP.computeIfAbsent(getWindowId(), k -> new ArrayList<>()).add(new Pair<>(ret, callback));
        return true;
    }

    /**
     * 移除窗口销毁监听
     *
     * @param callback
     */
    public void removeWindowDestroyEventListener(WindowDestroyListener callback) {
        WebViewApi.checkUIThread();
        List<Pair<Integer, WindowDestroyListener>> listeners = WINDOW_DESTROY_MAP.get(getWindowId());
        if (listeners == null) {
            return;
        }
        Iterator<Pair<Integer, WindowDestroyListener>> iterator = listeners.iterator();
        while (iterator.hasNext()) {
            Pair<Integer, WindowDestroyListener> pair = iterator.next();
            if (Objects.equals(pair.getValue(), callback)) {
                removeWindowDestroyEventListener_(pair.getKey());
                iterator.remove();
            }
        }
    }

    /**
     * 设置cookie使得前端可以访问需要验证的网络
     *
     * @param name
     * @param value
     * @param domain
     * @param path
     * @param isHttpOnly
     * @param isSecure
     * @param expires    只允许传入 -1.0D(退出程序失效) 0.0D(删除) 正数
     */
    public void addOrUpdateCookie(String name, String value, String domain, String path, boolean isHttpOnly, boolean isSecure, double expires) {
        WebViewApi.checkUIThread();
        if (StringUtils.isAnyBlank(name, value, domain, path)) {
            throw new IllegalArgumentException();
        }
        addOrUpdateCookie_(name, value, domain, path, isHttpOnly, isSecure, expires);
    }

    /**
     * 删除 Cookie
     * @param name
     * @param domain
     * @param path
     */
    public void deleteCookie(String name, String domain, String path) {
        WebViewApi.checkUIThread();
        if (StringUtils.isAnyBlank(name, domain, path)) {
            throw new IllegalArgumentException();
        }
        deleteCookie_(name, domain, path);
    }

    /**
     * 删除所有cookie
     */
    public void clearAllCookie() {
        WebViewApi.checkUIThread();
        clearAllCookie_();
    }

    /**
     * 窗口是否有效
     *
     * @return
     */
    public native boolean isValid_();

    /**
     * 设置窗口标题
     *
     * @param title
     */
    private native void setWindowTitle_(String title);

    /**
     * 打开调试工具
     */
    private native void openDevTools_();

    /**
     * 加载url
     *
     * @param url
     */
    private native void loadUrl_(String url);

    /**
     * 加载html字符串
     *
     * @param html
     */
    private native void loadHtmlString_(String html);

    /**
     * 重新加载
     */
    private native void reloadUrl_();

    /**
     * 查询回调
     *
     * @param index
     * @param success
     * @param jsonString
     */
    private native void queryCallback_(int index, boolean success, String jsonString);

    /**
     * 分发事件
     *
     * @param eventName
     * @param jsonString
     */
    private native void dispatchEvent_(String eventName, String jsonString);

    /**
     * 最小化窗口
     */
    private native void minimizeWindow_();

    /**
     * 窗口是否可见
     *
     * @return
     */
    private native boolean isWindowVisible_();

    /**
     * 关闭窗口
     *
     * @param force
     */
    private native void closeWindow_(boolean force);

    /**
     * 获取窗口矩形
     *
     * @return
     */
    private native Rect getWindowRect_();

    /**
     * 获取客户区矩形
     *
     * @return
     */
    private native Rect getClientRect_();

    /**
     * 闪烁
     */
    private native void flashWindow_();

    /**
     * 闪烁
     *
     * @param dwFlags
     * @param uCount
     * @param dwTimeout
     */
    private native void flashWindowEx_(int dwFlags, int uCount, int dwTimeout);

    /**
     * 获取窗口状态
     *
     * @return
     */
    private native int getWindowStatus_();

    /**
     * 获取窗口标题
     *
     * @return
     */
    private native String getWindowTitle_();

    /**
     * 获取窗口DPI
     *
     * @return
     */
    private native int getWindowDpi_();

    /**
     * 激活窗口
     */
    private native void activeWindow_();

    /**
     * 设置窗口置顶
     *
     * @param topmost
     */
    private native void setWindowTopMost_(boolean topmost);

    /**
     * 窗口是否置顶
     *
     * @return
     */
    private native boolean isWindowTopMost_();

    /**
     * 移动调整窗口大小
     *
     * @param x
     * @param y
     * @param width
     * @param height
     */
    private native void moveWindow_(int x, int y, int width, int height);

    /**
     * 调整窗口大小
     *
     * @param width
     * @param height
     */
    private native void resizeWindow_(int width, int height);

    /**
     * 显示窗口
     *
     * @param showType
     */
    private native void showWindow_(int showType);

    /**
     * 最大化窗口
     *
     * @param maximize
     */
    private native void maximizeWindow_(boolean maximize);

    /**
     * 获取窗口ID
     *
     * @return
     */
    private native int getWindowId_();

    /**
     * 获取窗口句柄
     *
     * @return
     */
    private native HWND getWindowHandle_();

    /**
     * 设置窗口启用
     *
     * @param enable
     */
    private native void setWindowEnable_(boolean enable);

    /**
     * 获取窗口启用
     *
     * @return
     */
    private native boolean isWindowEnabled_();

    /**
     * 设置窗口可缩放
     *
     * @param resizable
     */
    private native void setWindowResizable_(boolean resizable);

    /**
     * 运行在UI线程
     *
     * @param runnable
     */
    private native void runOnUI_(Runnable runnable);

    /**
     * 添加查询监听
     *
     * @param callback
     * @return
     */
    private native int addQueryListener_(QueryListener callback);

    /**
     * 移除查询监听
     *
     * @param id
     */
    private native void removeQueryListener_(int id);

    /**
     * 添加窗口关闭监听
     *
     * @param callback
     * @return
     */
    private native int addWindowCloseEventListener_(WindowCloseListener callback);

    /**
     * 移除窗口关闭监听
     *
     * @param id
     */
    private native void removeWindowCloseEventListener_(int id);

    /**
     * 添加窗口销毁监听
     *
     * @param callback
     * @return
     */
    private native int addWindowDestroyEventListener_(WindowDestroyListener callback);

    /**
     * 移除窗口销毁监听
     *
     * @param id
     */
    private native void removeWindowDestroyEventListener_(int id);


    /**
     * 设置cookie使得前端可以访问需要验证的网络
     *
     * @param name
     * @param value
     * @param domain
     * @param path
     * @param isHttpOnly
     * @param isSecure
     * @param expires
     */
    private native void addOrUpdateCookie_(String name, String value, String domain, String path, boolean isHttpOnly, boolean isSecure, double expires);

    /**
     * @param name
     * @param domain
     * @param path
     */
    private native void deleteCookie_(String name, String domain, String path);

    /**
     * 清空所有cookie
     */
    private native void clearAllCookie_();

    /**
     * @return
     */
    @Override
    public String toString() {
        return "WebWindow{" + "id=" + getId() + '}';
    }
}
